home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 6: Level 6 / 17 Bit - Level 6 (1998)(Epic Marketing)[!].iso / quartz / q1082.dms / q1082.adf / src.lzh / Fig / intspline.c < prev    next >
C/C++ Source or Header  |  1991-07-18  |  8KB  |  303 lines

  1. /* 
  2.  *    FIG : Facility for Interactive Generation of figures
  3.  *
  4.  *    Copyright (c) 1985 by Supoj Sutanthavibul (supoj@sally.UTEXAS.EDU)
  5.  *    January 1985.
  6.  *    1st revision : Aug 1985.
  7.  *
  8.  *    %W%    %G%
  9. */
  10. #include "fig.h"
  11. #include "resources.h"
  12. #include "alloc.h"
  13. #include "func.h"
  14. #include "object.h"
  15. #include "paintop.h"
  16.  
  17. extern            (*canvas_kbd_proc)();
  18. extern            (*canvas_locmove_proc)();
  19. extern            (*canvas_leftbut_proc)();
  20. extern            (*canvas_middlebut_proc)();
  21. extern            (*canvas_rightbut_proc)();
  22. extern            null_proc();
  23. extern            set_popupmenu();
  24.  
  25. extern int        cur_line_style, line_thickness;
  26. extern float        cur_styleval;
  27. extern int        cur_color;
  28. extern int        fix_x, fix_y, cur_x, cur_y;
  29. extern int        cur_command;
  30. extern int        manhattan_mode, mountain_mode;
  31. extern int        autoforwardarrow_mode;
  32. extern int        autobackwardarrow_mode;
  33. extern F_compound    objects;
  34. extern int        num_point;
  35. extern int        DEBUG;
  36. extern F_point        *first_point, *cur_point;
  37.  
  38. int            create_intsplineobject();
  39.             init_intspline_drawing();
  40.  
  41. draw_intspline_selected()
  42. {
  43.     canvas_kbd_proc = null_proc;
  44.     canvas_locmove_proc = null_proc;
  45.     canvas_leftbut_proc = init_intspline_drawing;
  46.     canvas_middlebut_proc = null_proc;
  47.     canvas_rightbut_proc = set_popupmenu;
  48.     set_cursor(&arrow_cursor);
  49.     reset_action_on();
  50.     }
  51.  
  52. init_intspline_drawing(x, y)
  53. int    x, y;
  54. {
  55.     init_line_drawing(x, y);
  56.     canvas_middlebut_proc = create_intsplineobject;
  57.     canvas_rightbut_proc = null_proc;
  58.     }
  59.  
  60. create_intsplineobject(x, y)
  61. int    x, y;
  62. {
  63.     extern F_arrow    *forward_arrow(), *backward_arrow();
  64.     F_spline    *spline;
  65.  
  66.     if (x != fix_x || y != fix_y) get_intermediatepoint(x, y);
  67.     draw_elasticline();
  68.     if (num_point <= 2) {
  69.         pw_vector(canvas_pixwin, first_point->x, first_point->y,
  70.             cur_point->x, cur_point->y, PAINT, 0);
  71.         if (num_point == 1) free((char*)cur_point);
  72.         free((char*)first_point);
  73.         draw_intspline_selected();
  74.         return;
  75.         }
  76.     if (NULL == (Spline_malloc(spline))) {
  77.         if (num_point == 1) free((char*)cur_point);
  78.         free((char*)first_point);
  79.         put_msg(Err_mem);
  80.         return;
  81.         }
  82.     spline->style = cur_line_style;
  83.     spline->thickness = line_thickness;
  84.     spline->style_val = cur_styleval;
  85.     spline->color = cur_color;
  86.     spline->depth = 0;
  87.     spline->area_fill = NULL;
  88.     spline->pen = NULL;
  89.     spline->points = first_point;
  90.     spline->controls = NULL; 
  91.     spline->next = NULL; 
  92.     cur_x = cur_y = fix_x = fix_y = 0; /* used in draw_movingpoint */
  93.     draw_movingpoint(spline->points, INV_PAINT); /* erase control vector */
  94.     spline->for_arrow = NULL;
  95.     spline->back_arrow  = NULL;
  96.     if (cur_command == F_CLOSED_INTSPLINE) {
  97.         spline->type = T_CLOSED_INTERPOLATED;
  98.         num_point++;
  99.         append_point(first_point->x, first_point->y, &cur_point);
  100.         }
  101.     else {
  102.         spline->type = T_OPEN_INTERPOLATED;
  103.         if (autoforwardarrow_mode) spline->for_arrow = forward_arrow();
  104.         if (autobackwardarrow_mode) spline->back_arrow = backward_arrow();
  105.         }
  106.     make_control_points(spline);
  107.     pw_batch_on(canvas_pixwin);
  108.     draw_intspline(spline, PAINT);
  109.     if (DEBUG) {
  110.         int    xmin, ymin, xmax, ymax;
  111.         spline_bound(spline, &xmin, &ymin, &xmax, &ymax);
  112.         draw_rectbox(xmin, ymin, xmax, ymax, PAINT);
  113.         }
  114.     pw_batch_off(canvas_pixwin);
  115.     clean_up();
  116.     set_action_object(F_CREATE, O_SPLINE);
  117.     insert_spline(&objects.splines, spline);
  118.     set_latestspline(spline);
  119.     set_modifiedflag();
  120.     draw_intspline_selected();
  121.     }
  122.  
  123. /* Tension : 0 (min) -> 1 (max)    */
  124.  
  125. #define        round(x)    ((int) (x + .5))
  126.  
  127. create_control_list(s)
  128. F_spline    *s;
  129. {
  130.     F_point        *p;
  131.     F_control    *cp;
  132.  
  133.     if (NULL == (Control_malloc(cp))) {
  134.         put_msg(Err_mem);
  135.         return(-1);
  136.         }
  137.     s->controls = cp;
  138.     for (p = s->points->next; p != NULL; p = p->next) {
  139.         if (NULL == (Control_malloc(cp->next))) {
  140.         put_msg(Err_mem);
  141.         return(-1);
  142.         }
  143.         cp = cp->next;
  144.         }
  145.     cp->next = NULL;
  146.     return(1);
  147.     }
  148.  
  149. make_control_points(s)
  150. F_spline    *s;
  151. {
  152.     if (-1 == create_control_list(s)) return;
  153.  
  154.     remake_control_points(s);
  155.     }
  156.  
  157. remake_control_points(s)
  158. F_spline    *s;
  159. {
  160.     if (s->type == T_CLOSED_INTERPOLATED)
  161.         compute_cp(s->points, s->controls, CLOSED_PATH);
  162.     else
  163.         compute_cp(s->points, s->controls, OPEN_PATH);
  164.     }
  165.  
  166. draw_intspline(s, op)
  167. F_spline    *s;
  168. int        op;
  169. {
  170.     F_point        *p1, *p2;
  171.     F_control    *cp1, *cp2;
  172.  
  173.     p1 = s->points;
  174.     cp1 = s->controls;
  175.     if (s->for_arrow)
  176.         draw_arrow(round(cp1->rx), round(cp1->ry), p1->x,
  177.             p1->y, s->for_arrow, op);
  178.     for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
  179.         p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
  180.         bezier_spline((float)p1->x, (float)p1->y, cp1->rx, cp1->ry,
  181.             cp2->lx, cp2->ly, (float)p2->x, (float)p2->y, op);
  182.         }
  183.     if (s->back_arrow)
  184.         draw_arrow(round(cp1->lx), round(cp1->ly), p1->x,
  185.             p1->y, s->back_arrow, op);
  186.     }
  187.  
  188. #define        T        0.45
  189. #define        _2xPI        6.2832
  190. #define        _1dSQR2        0.7071
  191. #define        _SQR2        1.4142
  192.  
  193. compute_cp(points, controls, path)
  194. F_point        *points;
  195. F_control    *controls;
  196. int        path;
  197. {
  198.     F_control    *cp, *cpn;
  199.     F_point        *p, *p2, *pk;    /* Pk is the next-to-last point. */
  200.     float        dx, dy;
  201.     float        x1, y1, x2, y2, x3, y3;
  202.     float        l1, l2, theta1, theta2;
  203.  
  204.     x1 = points->x;  y1 = points->y;
  205.     pk = p2 = points->next;
  206.     x2 = p2->x;  y2 = p2->y;
  207.     p = p2->next;
  208.     x3 = p->x;  y3 = p->y;
  209.  
  210.     dx = x1 - x2;
  211.     dy = y2 - y1;
  212.     l1 = sqrt((double)(dx*dx + dy*dy));
  213.     theta1 = atan2((double)dy, (double)dx);
  214.     dx = x3 - x2;
  215.     dy = y2 - y3;
  216.     l2 = sqrt((double)(dx*dx + dy*dy));
  217.     theta2 = atan2((double)dy, (double)dx);
  218.     /* -PI <= theat1, theta2 <= PI */
  219.     if (theta1 < 0) theta1 += _2xPI;
  220.     if (theta2 < 0) theta2 += _2xPI;
  221.     /* 0 <= theat1, theta2 < 2PI */
  222.  
  223.     cp = controls->next;
  224.     control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  225.     /* control points for (x2, y2) */
  226.     if (path == OPEN_PATH) {
  227.         controls->lx = 0.0; controls->ly = 0.0;
  228.         controls->rx = (x1 + 3*cp->lx)/4; controls->ry = (y1 + 3*cp->ly)/4;
  229.         cp->lx = (3*cp->lx + x2)/4; cp->ly = (3*cp->ly + y2)/4;
  230.         }
  231.  
  232.     while (1) {
  233.         x2 = x3; y2 = y3;
  234.         l1 = l2;
  235.         if (theta2 >= M_PI)
  236.         theta1 = theta2 - M_PI;
  237.         else
  238.         theta1 = theta2 + M_PI;
  239.         if ((p = p->next) == NULL) break;
  240.         pk = pk->next;
  241.         x3 = p->x; y3 = p->y;
  242.         dx = x3 - x2;
  243.         dy = y2 - y3;
  244.         l2 = sqrt((double)(dx*dx + dy*dy));
  245.         theta2 = atan2((double)dy, (double)dx);
  246.         if (theta2 < 0) theta2 += _2xPI;
  247.         cp = cp->next;
  248.         control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  249.         };
  250.  
  251.     if (path == CLOSED_PATH) {
  252.         dx = p2->x - x2;
  253.         dy = y2 - p2->y;
  254.         l2 = sqrt((double)(dx*dx + dy*dy));
  255.         theta2 = atan2((double)dy, (double)dx);
  256.         if (theta2 < 0) theta2 += _2xPI;
  257.         cp = cp->next;
  258.         control_points(x2, y2, l1, l2, theta1, theta2, T, cp);
  259.         controls->lx = cp->lx; controls->ly = cp->ly;
  260.         controls->rx = cp->rx; controls->ry = cp->ry;
  261.         }
  262.     else {
  263.         cpn = cp->next;
  264.         cpn->lx = (3*cp->rx + x2) / 4; cpn->ly = (3*cp->ry + y2) / 4;
  265.         cpn->rx = 0.0; cpn->ry = 0.0;
  266.         cp->rx = (pk->x + 3*cp->rx) / 4; cp->ry = (pk->y + 3*cp->ry) / 4;
  267.         }
  268.     }
  269.  
  270. /*
  271. The parameter t is the tension.  It must range in [0, 1].
  272. The bigger the value of t, the higher the tension.
  273. */
  274.  
  275. control_points(x, y, l1, l2, theta1, theta2, t, cp)
  276. float    x, y, l1, l2, theta1, theta2, t;
  277. F_control    *cp;
  278. {
  279.     float    s, theta, r = 1 - t;
  280.  
  281.     /* 0 <= theat1, theta2 < 2PI */
  282.  
  283.     theta = (theta1 + theta2) / 2;
  284.  
  285.     if (theta1 > theta2) {
  286.         s = sin((double)(theta-theta2));
  287.         theta1 = theta + M_PI_2;
  288.         theta2 = theta - M_PI_2;
  289.         }
  290.     else {
  291.         s = sin((double)(theta2-theta));
  292.         theta1 = theta - M_PI_2;
  293.         theta2 = theta + M_PI_2;
  294.         }
  295.     if (s > _1dSQR2) s = _SQR2 - s;
  296.     s *= r;
  297.     l1 *= s; l2 *= s;
  298.     cp->lx = x + l1 * cos((double)theta1);
  299.     cp->ly = y - l1 * sin((double)theta1);
  300.     cp->rx = x + l2 * cos((double)theta2);
  301.     cp->ry = y - l2 * sin((double)theta2);
  302.     }
  303.